/// @file Utilities.cpp
/// @brief provides central library of basic and routine funtions

#include "Utilities.h"
#include "Configuration.h"

ngl::Vector Utilities::normaliseVector
                            (
                                const ngl::Vector _vector,
                                const ngl::Vector _zeroVector
                            )
{
    if (_vector.length() < 0.0001)
    {
        //zero vector
        return _zeroVector;
    }
    else
    {
        ngl::Vector r = _vector;
        r.normalize();
        return r;
    }
}

ngl::Vector Utilities::scaleVectorBy
                                (
                                    const ngl::Vector _vector,
                                    const float _scale,
                                    const ngl::Vector _zeroVector
                                )
{
    ngl::Vector tmp = Utilities::normaliseVector(_vector, _zeroVector);
    tmp = tmp * _scale;

    return tmp;
}

int Utilities::getNext
                    (
                        const int _current,
                        const int _min,
                        const int _max
                    )
{
    int tmp = _current + 1;
    if (tmp > _max) tmp = _min;

    return tmp;
}

int Utilities::getPrevious
                    (
                        const int _current,
                        const int _min,
                        const int _max
                    )
{
    int tmp = _current - 1;
    if (tmp < _min) tmp = _max;

    return tmp;
}

bool Utilities::isObjectInsideSphere
                                (
                                    const ngl::Vector _center1,
                                    const float _radius1,
                                    const ngl::Vector _center2,
                                    const float _radius2,
                                    const ngl::Vector _objectVelocity
                                )
{
    //assume no collision by default
    bool isColliding = false;

    //get vector from center1 and center2
    ngl::Vector vector = _center1 - _center2;

    //get the angle of difference between the taret vector and the velocity of the object
    float angle = vector.dot(_objectVelocity);

    if (angle < 0)
    {
        //the boid is going away from the sphere => no collision possible
        isColliding = false;
    }
    else
    {
        //get length of separation from center1 to center2
        float separationDistance = vector.length();

        isColliding = (separationDistance <= _radius1 + _radius2);
    }

    if (Configuration::s_debug) std::cout << "Utilities Check sphere collision : " << vector << "\t" << _objectVelocity << "\t" << angle << "\tcolliding : " << isColliding << std::endl;

    return isColliding;
}

ngl::Vector Utilities::getWorkaroundVelocity
                                        (
                                            const ngl::Vector _center1,
                                            const float _radius1,
                                            const ngl::Vector _center2,
                                            const bool _enable2DTopView
                                        )
{
    //get upper and lower limits
    std::vector<ngl::Vector> limits;
    limits.push_back(ngl::Vector(_center1.m_x - _radius1, _center1.m_y, _center1.m_z));
    limits.push_back(ngl::Vector(_center1.m_x + _radius1, _center1.m_y, _center1.m_z));
    if (!_enable2DTopView) limits.push_back(ngl::Vector(_center1.m_x, _center1.m_y - _radius1, _center1.m_z));
    if (!_enable2DTopView) limits.push_back(ngl::Vector(_center1.m_x, _center1.m_y + _radius1, _center1.m_z));
    limits.push_back(ngl::Vector(_center1.m_x, _center1.m_y, _center1.m_z - _radius1));
    limits.push_back(ngl::Vector(_center1.m_x, _center1.m_y, _center1.m_z + _radius1));

    ngl::Vector targetVector = limits[0] - _center2;;
    float minDistance = targetVector.length();
    float dist;
    ngl::Vector tmpVector;
    for (int i  = 1; i < limits.size(); i++)
    {
        //find the point that is closer to the object
        tmpVector = limits[i] - _center2;
        dist = tmpVector.length();

        if (dist < minDistance)
        {
            //this point is closer, save it
            minDistance = dist;
            targetVector = tmpVector;
        }
    }

    //set y vel to 0 if we are in 2d top view
    if (_enable2DTopView) targetVector.m_y = 0;

    if (Configuration::s_debug) std::cout << "Utilities - getWorkaroundVelocity : " << minDistance << "\t" << targetVector << std::endl;


    return targetVector;
}
